package com.oliet.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.oliet.common.vo.file.DownloadVO;
import com.oliet.common.vo.file.FileResourceVO;
import com.oliet.common.vo.page.PageVO;
import com.oliet.entity.Dictionary;
import com.oliet.entity.FileResources;
import com.oliet.entity.base.BaseEntity;
import com.oliet.exception.CustomException;
import com.oliet.exception.ErrorEnum;
import com.oliet.mapper.DictionaryMapper;
import com.oliet.mapper.FileResourcesMapper;
import com.oliet.service.FileResourcesService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.oliet.util.CodeUtils;
import com.oliet.util.MyFileUtils;
import lombok.SneakyThrows;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.ArchiveException;
import org.apache.commons.compress.archivers.ArchiveInputStream;
import org.apache.commons.compress.archivers.ArchiveStreamFactory;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import org.apache.commons.compress.utils.IOUtils;
import org.apache.commons.compress.utils.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author JZP
 * @since 2023-12-22
 */
@Service
public class FileResourcesServiceImpl extends ServiceImpl<FileResourcesMapper, FileResources> implements FileResourcesService {

    @Value("${fileConfig.basePath}")
    private String BASE_PATH;
    @Value("${fileConfig.uploadPath}")
    private String UPLOAD_PATH;

    @Autowired
    private DictionaryMapper dictionaryMapper;

    @Override
    public void upload(MultipartFile file) {
        if (file.isEmpty()) {
            throw new CustomException(ErrorEnum.INVALID_PARAMETER);
        }
        // 获取文件原始名
        String originalFilename = file.getOriginalFilename();
        // 获取文件后缀
        String suffix = MyFileUtils.getSuffix(originalFilename);
        // 获取保存文件名
        String fileCode = CodeUtils.getCommonCode();
        String saveFilename = fileCode + StrUtil.DOT + suffix;
        // 获取保存文件夹
        String saveFolder = MyFileUtils.createSaveFolder(UPLOAD_PATH, originalFilename);
        // 创建文件对象
        String saveFilePath = saveFolder + File.separator + saveFilename;
        File destFile = new File(saveFilePath);
        // 保存文件
        try {
            file.transferTo(destFile);
        } catch (IOException e) {
            throw new CustomException(ErrorEnum.FILE_SAVE_FAILED);
        }
        //保存数据库
        FileResources po = new FileResources();
        po.setCode(fileCode);
        po.setFileName(originalFilename);
        po.setFilePath(saveFilePath);
        po.setFileSuffix(suffix);
        po.setFileType(MyFileUtils.getFileSaveType(originalFilename));
        po.setFileSize(file.getSize());
        this.save(po);
    }

    @Override
    public void batchUpload(MultipartFile[] files) {
        if (ObjectUtil.isEmpty(files)) {
            throw new CustomException(ErrorEnum.INVALID_PARAMETER);
        }
        for (MultipartFile file : files) {
            this.upload(file);
        }
    }

    @Transactional
    @Override
    public void batchUploadOther(MultipartFile[] files, String classType, String fileType, String displayPosition) {
        if (ObjectUtil.isEmpty(files)) {
            throw new CustomException(ErrorEnum.INVALID_PARAMETER);
        }
        for (MultipartFile file : files) {
            // 获取文件原始名
            String originalFilename = file.getOriginalFilename();
            // 获取文件后缀
            String suffix = MyFileUtils.getSuffix(originalFilename);
            if ("zip".equals(suffix)) {
                this.uploadZip(file, classType, fileType, displayPosition);
            } else {
                this.upload(file, classType, fileType, displayPosition);
            }
        }
    }


    private void upload(MultipartFile file, String classType, String fileType, String displayPosition) {
        if (file.isEmpty()) {
            throw new CustomException(ErrorEnum.INVALID_PARAMETER);
        }
        // 获取文件原始名
        String originalFilename = file.getOriginalFilename();
        // 获取文件后缀
        String suffix = MyFileUtils.getSuffix(originalFilename);
        // 获取保存文件名
        String fileCode = CodeUtils.getCommonCode();
        String saveFilename = fileCode + StrUtil.DOT + suffix;
        // 获取保存文件夹
        String saveFolder = MyFileUtils.createSaveFolder(UPLOAD_PATH, originalFilename);
        // 创建文件对象
        String saveFilePath = saveFolder + File.separator + saveFilename;
        File destFile = new File(saveFilePath);
        // 保存文件
        try {
            file.transferTo(destFile);
        } catch (IOException e) {
            throw new CustomException(ErrorEnum.FILE_SAVE_FAILED);
        }
        //查询字典
        List<Dictionary> dictionaryList = this.dictionaryMapper.selectList(null);
        Map<String, String> dictMap = dictionaryList.stream().collect(Collectors.toMap(Dictionary::getItemCode, Dictionary::getItemName));
        //保存数据库
        FileResources po = FileResources.builder()
                .fileName(originalFilename)
                .filePath(saveFilePath)
                .fileSuffix(suffix)
                .fileSize(file.getSize())
                .classType(classType)
                .classTypeName(dictMap.get(classType))
                .fileType(fileType)
                .fileTypeName(dictMap.get(fileType))
                .saveType(MyFileUtils.getFileSaveType(originalFilename))
                .displayPosition(displayPosition)
                .displayPositionName(dictMap.get(displayPosition))
                .build();
        po.setCode(fileCode);
        this.save(po);
    }

    public void uploadZip(MultipartFile file, String classType, String fileType, String displayPosition) {
        if (file.isEmpty()) {
            throw new CustomException(ErrorEnum.INVALID_PARAMETER);
        }
        //保存压缩文件
        File zipFile = this.saveZip(file);
        //解压缩
        File unzipFolder = this.unzip(zipFile);
        //获取文件夹中的html文件
        File htmlFile = this.findHtmlFile(unzipFolder);
        //查询字典
        List<Dictionary> dictionaryList = this.dictionaryMapper.selectList(null);
        Map<String, String> dictMap = dictionaryList.stream().collect(Collectors.toMap(Dictionary::getItemCode, Dictionary::getItemName));
        //保存数据库
        FileResources po = FileResources.builder()
                .fileName(htmlFile.getName())
                .filePath(htmlFile.getAbsolutePath())
                .fileSuffix("html")
                .fileSize(file.getSize())
                .classType(classType)
                .classTypeName(dictMap.get(classType))
                .fileType(fileType)
                .fileTypeName(dictMap.get(fileType))
                .saveType(MyFileUtils.getFileSaveType(file.getOriginalFilename()))
                .displayPosition(displayPosition)
                .displayPositionName(dictMap.get(displayPosition))
                .unzipFolder(unzipFolder.getAbsolutePath())
                .build();
        po.setCode(CodeUtils.getCommonCode());
        System.out.println("===上传文件po打印=="+ JSONObject.toJSONString(po));
        this.save(po);
        //删除压缩包
        if (zipFile.exists()) {
            zipFile.delete();
        }
    }


    public File saveZip(MultipartFile file) {
        // 获取文件原始名
        String originalFilename = file.getOriginalFilename();
        // 获取文件后缀
        String suffix = MyFileUtils.getSuffix(originalFilename);
        // 获取保存文件名
        String fileCode = CodeUtils.getCommonCode();
        String saveFilename = fileCode + StrUtil.DOT + suffix;
        // 获取保存文件夹
        String saveFolder = MyFileUtils.createSaveFolder(UPLOAD_PATH, originalFilename);
        // 创建文件对象
        String saveFilePath = saveFolder + File.separator + saveFilename;
        File destFile = new File(saveFilePath);
        // 保存文件
        try {
            file.transferTo(destFile);
        } catch (IOException e) {
            throw new CustomException(ErrorEnum.FILE_SAVE_FAILED);
        }
        return destFile;
    }

    @SneakyThrows
    public File unzip(File zipFile) {
        // 获取压缩文件的路径
        String zipFilePath = zipFile.getAbsolutePath();
        // 构建解压目标文件夹路径
        String destDirPath = zipFilePath.substring(0, zipFilePath.lastIndexOf(".zip"));
        //解压
        unzipFolder(zipFilePath, destDirPath);
        return new File(destDirPath);
    }

    public static File unzipFolder(String zipFilePath, String destDirPath) throws IOException {
        File destDir = new File(destDirPath);
        if (!destDir.exists()) {
            destDir.mkdirs();
        }
        try (FileInputStream fis = new FileInputStream(zipFilePath);
             BufferedInputStream bis = new BufferedInputStream(fis);
             ArchiveInputStream ais = new ZipArchiveInputStream(bis)) {

            ArchiveEntry entry;
            while ((entry = ais.getNextEntry()) != null) {
                String entryName = entry.getName();
                File entryFile = new File(destDir, entryName);

                if (entry.isDirectory()) {
                    entryFile.mkdirs();
                } else {
                    try (OutputStream os = new FileOutputStream(entryFile);
                         BufferedOutputStream bos = new BufferedOutputStream(os)) {
                        IOUtils.copy(ais, bos);
                    }
                }
            }
        }

        return destDir;
    }


    public static File findHtmlFile(File directory) {
        File[] files = directory.listFiles();
        if (files != null) {
            for (File file : files) {
                if (!file.isDirectory() && file.getName().endsWith(".html")) {
                    return file;
                }
            }
        }
        throw new CustomException(ErrorEnum.ZIP_FORMAT_ERROR);
    }

    @Override
    public DownloadVO download(Long id) throws IOException {
        if (ObjectUtil.isNull(id)) {
            throw new CustomException(ErrorEnum.INVALID_PARAMETER);
        }
        // 获取文件
        FileResources po = this.getById(id);
        if (ObjectUtil.isNull(po)) {
            throw new CustomException(ErrorEnum.DATA_DOES_NOT_EXIST);
        }
        File file = new File(po.getFilePath());
        if (!file.exists()) {
            throw new CustomException(ErrorEnum.FILE_IS_DAMAGED);
        }
        // 读取文件内容并创建文件资源
        byte[] fileContent = Files.readAllBytes(file.toPath());
        ByteArrayResource resource = new ByteArrayResource(fileContent);
        return DownloadVO.builder()
                .fileName(po.getFileName())
                .resource(resource)
                .build();
    }

    @Override
    public void delete(Long id) {
        FileResources po = this.getById(id);
        if (ObjectUtil.isNull(po)) {
            throw new CustomException(ErrorEnum.DATA_DOES_NOT_EXIST);
        }
        //删除数据
        this.removeById(id);
        if (StrUtil.isNotBlank(po.getUnzipFolder())){
            //删除本地文件夹
            File file = new File(po.getUnzipFolder());
            deleteFolder(file);
        }else{
            //删除本地文件
            File file = new File(po.getFilePath());
            if (file.exists()) {
                file.delete();
            }
        }

    }

    public static void deleteFolder(File folder) {
        if (folder.exists()) {
            File[] files = folder.listFiles();
            if (files != null) {
                for (File file : files) {
                    if (file.isDirectory()) {
                        // 递归删除子文件夹
                        deleteFolder(file);
                    } else {
                        // 删除文件
                        file.delete();
                    }
                }
            }
            // 删除空文件夹
            folder.delete();
        }
    }

    @Override
    public PageVO<FileResourceVO> pageList(Long pageNo, Long pageSize, String classType, String fileType, String displayPosition, String search) {
        //分页查询
        Page<FileResources> page = new Page<>(pageNo, pageSize);
        Page<FileResources> poData = this.page(page, new LambdaQueryWrapper<FileResources>()
                .eq(StringUtils.isNotBlank(classType), FileResources::getClassType, classType)
                .eq(StringUtils.isNotBlank(fileType), FileResources::getFileType, fileType)
                .eq(StringUtils.isNotBlank(displayPosition), FileResources::getDisplayPosition, displayPosition)
                .like(StringUtils.isNotBlank(search), FileResources::getFileName, search)
                .orderByDesc(BaseEntity::getDateCreated)
        );
        List<FileResourceVO> voList = FileResourceVO.poListConverVoList(poData.getRecords(), BASE_PATH, UPLOAD_PATH);
        PageVO<FileResourceVO> pageVo = new PageVO<>(poData.getCurrent(), poData.getSize(), poData.getTotal(), voList);
        return pageVo;
    }


}

